package com.ifinc.common.web.frame;

import com.ifinc.common.exception.ConfigException;
import com.ifinc.common.utils.ExceptionUtils;
import com.ifinc.common.web.frame.define.Param;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * User: luotao
 * Date: 13-11-27
 * Time: 13:53
 */
public abstract class ProxyBase {
    protected String className;

    protected String methodName;

    protected Object invokeObject;

    protected String basePackage;

    protected Class aClass;

    public String getBasePackage() {
        return basePackage;
    }


    public void setClassInfo(String basePackage,String className,String methodName){
        this.basePackage=basePackage;
        this.className=className;
        this.methodName=methodName;
    }

    public void initObject() {
        try {
            aClass = Class.forName(basePackage + "." + className);
            Constructor constructor = aClass.getConstructor();
            constructor.setAccessible(true);
            invokeObject = constructor.newInstance();
        } catch (ClassNotFoundException e) {
            ExceptionUtils.printException(e);
            throw new ConfigException("not found className %s", className);
        } catch (NoSuchMethodException e) {
            ExceptionUtils.printException(e);
            throw new ConfigException("not found methodName %s", methodName);
        } catch (InstantiationException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        } catch (IllegalAccessException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        } catch (InvocationTargetException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        }
    }

    public Object execute() {
        try {
            verify();
            Method method = aClass.getMethod(methodName);
            method.setAccessible(true);
            Class methodReturnType = method.getReturnType();
            checkReturn(methodReturnType);
            Object result = method.invoke(invokeObject);
            return result;
        } catch (NoSuchMethodException e) {
            ExceptionUtils.printException(e);
            throw new ConfigException("not found methodName %s", methodName);
        } catch (IllegalAccessException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        } catch (InvocationTargetException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        }
    }

    public void setParams(Map reqParam, Map sessionMap, Map headerMap) {
        if (!(invokeObject instanceof Param)) {
            throw new ConfigException("class:%s must implements " + Param.class.getName(), className);
        }
        Param param = (Param) invokeObject;
        param.setReqParam(reqParam);
        param.setSessionMap(sessionMap);
        param.setHeaderParam(headerMap);
    }

    public void verify() {
        if (!(invokeObject instanceof Param)) {
            throw new ConfigException("class:%s must implements " + Param.class.getName(), className);
        }
        Param param = (Param) invokeObject;
        param.verify(methodName);
    }

    public Map<String, Object> getSessionMap() {
        if (!(invokeObject instanceof Param)) {
            throw new ConfigException("class:%s must implements " + Param.class.getName(), className);
        }
        Param param = (Param) invokeObject;
        return param.getSessionMap();
    }

    public Map<String, Object> getResultMap() {
        if (!(invokeObject instanceof Param)) {
            throw new ConfigException("class:%s must implements " + Param.class.getName(), className);
        }
        Param param = (Param) invokeObject;
        return param.getResultMap();
    }

    public abstract void checkReturn(Class clz);
}
